﻿using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.Globalization;
using LocalView;
using DataType;
using Google.GData.Client;
using Google.Contacts;
using Google.Documents;
using Google.GData.Documents;
using System.IO;
using Google.GData.AccessControl;
using Word = Microsoft.Office.Interop.Word;
using Utilities;

namespace OfficeInCloudWord2003Addin2
{
    public class WordLocalView : ILocalView
    {
        private bool isLoggedIn; 

        public delegate void StateNotify(string key);

        private global::System.Object missing = global::System.Type.Missing;

        public Word.Application m_App;

        public override event EventHandler<Credentials> Login;
        public override event EventHandler<FeedWrapper<Contact>> GetContacts;
        public override event EventHandler<FeedWrapper<Document>> GetDocuments;
        public override event EventHandler<FeedWrapper<Document>> GetFolders;
        public override event EventHandler<DocumentInfo> UploadDocument;
        public override event EventHandler<DocumentInfo> UpdateDocument;
        public override event EventHandler<DownloadInfo> DownloadDocument;
        public override event EventHandler<ShareInfoCollection> ShareDocument;
        public override event EventHandler<ShareInfoCollection> GetDocumentAcl;
        public override event EventHandler<DocumentInfo> LookForDocument;
        public override event EventHandler<DocumentInfo> OpenDocumentInCloud;
        public override event EventHandler<ContactInfo> AddContact; 

        private DbOperations m_dbOperations;
        public StateNotify m_LoadState;
        public StateNotify m_StoreState;

        public WordLocalView(Word.Application App, DbOperations dbOperations)
        {
            m_App = App;
            m_DocInfo = null;
            m_dbOperations = dbOperations;
            isLoggedIn = false;
        }

        public override string GetDocumentPath()
        {
            return m_App.ActiveDocument.FullName;
        }

        public override string GetDocumentName()
        {
            return m_App.ActiveDocument.Name;
        }

        public override void DoLogin(Credentials cred)
        {
            if (Login != null)
                Login(this, cred);
            isLoggedIn = true;
        }

        public override void DoDownloadDocument(DownloadInfo info)
        {
            if (DownloadDocument != null)
                DownloadDocument(this, info);
        }

        public override void DoGetContacts(FeedWrapper<Contact> feed)
        {
            if (GetContacts != null)
                GetContacts(this, feed);
        }

        public void DoGetContactsAsync(NotifyDelegate<Contact> Notify)
        {
            if (GetContacts != null)
            {
                DoIterationASync<Contact> Iteration = new DoIterationASync<Contact>(this.GetContacts, Notify, this.dummy);
                Iteration.StartAction();
            }
        }

        public override void DoGetDocuments(FeedWrapper<Document> feed)
        {
            if (GetDocuments != null)
                GetDocuments(this, feed);
        }

        public void DoGetDocumentsAsync(NotifyDelegate<Document> Notify)
        {
            if (GetDocuments != null)
            {
                DoIterationASync<Document> Iteration = new DoIterationASync<Document>(this.GetDocuments, Notify, this.dummy);
                Iteration.StartAction();
            }
        }

        private void saveDocument()
        {
            Word.WdAlertLevel wd = m_App.DisplayAlerts;

            try
            {
                m_App.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;

                string fname = m_App.ActiveDocument.FullName;
                string docName1 = m_App.ActiveDocument.Name;

                if (!System.IO.Path.IsPathRooted(fname))
                {
                    object path = Utilities.Path.documentPath + "\\" + m_App.ActiveDocument.FullName;
                    m_App.ActiveDocument.SaveAs(ref path,
                                    ref missing,
                                    ref missing, //password
                                    ref missing, //writeRefPassword
                                    ref missing, //readOnlyRecommended
                                    ref missing, //createBackup
                                    ref missing,
                                    ref missing,
                                    ref missing,
                                    ref missing,
                                    ref missing,
                                    ref missing,
                                    ref missing,
                                    ref missing,
                                    ref missing,
                                    ref missing);
                }
                else
                    m_App.ActiveDocument.Save();
            }
            finally
            {
                m_App.DisplayAlerts = wd;
            }
        }

        public override void DoSaveDocumentInCloud()
        {
            saveDocument();
            if (UploadDocument != null)
            {
                m_DocInfo = new DocumentInfo(m_App.ActiveDocument.FullName, m_App.ActiveDocument.Name);
                UploadDocument(this, m_DocInfo);
                m_dbOperations.DoRegisterLocalCopy(m_DocInfo);
            }
        }

        public override void Merge(Document dt, ILocalView.CollisionWinner winner)
        {
            Document.DownloadType type = Document.DownloadType.doc;
            DownloadInfo info = new DownloadInfo(dt, type);
            DownloadDocument(this, info);

            //get new DocumentEnty
            //DoLookupRemoteCopy(m_DocInfo);

            Word.Document localWb = m_App.ActiveDocument;
            string tmpPath = localWb.FullName + "_tmp.doc";

            FileInfo fileInfo = new FileInfo(tmpPath);
            FileStream stream = fileInfo.Open(FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
            CommonOperations.DoSaveContent(stream, info.m_Stream);

            MergeContent(tmpPath);

            fileInfo.Delete();

            //throw new NotImplementedException();
        }

        private void MergeContent(string serverCopyPath)
        {
            object MergeTarget = Word.WdMergeTarget.wdMergeTargetCurrent;
            object DetectFormatChanges = true;
            object UseFormattingFrom = Word.WdUseFormattingFrom.wdFormattingFromCurrent;
            object AddToRecentFiles = true;

            m_App.ActiveDocument.Merge(serverCopyPath, ref MergeTarget,
                ref DetectFormatChanges, ref UseFormattingFrom,
                ref AddToRecentFiles);

            m_App.ActiveDocument.Save();
        }

       
        public override void DoLookupRemoteCopy(DocumentInfo info)
        {
            //at first look for document id in db, if no document then exception happens
            m_dbOperations.DoLookupRemoteCopy(info);

            if (info.m_RemoteId == null) return; 

            if (LookForDocument != null)
                LookForDocument(this, info);
        }

        public override void DoUpdateDocument()
        {

            if (UpdateDocument != null)
            {
                m_App.ActiveDocument.Save();
                UpdateDocument(this, m_DocInfo);
            }
            //try{
            //    if (UpdateDocument != null)
            //    {
            //        m_App.ActiveDocument.Save();

            //        UpdateDocument(this, m_DocInfo);
            //    }
            //}
            //catch(GDataRequestException e)
            //{
            //    //create later lookup for type depending extension using DocumentEntry.IsSpreadsheet and so on
            //    Document.DownloadType type = Document.DownloadType.doc;
            //    Document dt = new Document();
            //    dt.AtomEntry = m_DocInfo.m_DocEntry;
            //    DownloadInfo info = new DownloadInfo(dt, type);
            //    DownloadDocument(this, info);
                
            //    //get new DocumentEnty
            //    DoLookupRemoteCopy(m_DocInfo);

            //    Word.Document wb = m_App.ActiveDocument;
            //    string tmpPath = wb.Path + "\\" + wb.Name + "_tmp.doc";

            //    FileInfo fileInfo = new FileInfo(tmpPath);
            //    FileStream stream = fileInfo.Open(FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
            //    CommonOperations.DoSaveDocumentContent(stream, info.m_Stream);

            //    MergeDocumentWith(tmpPath);

            //    fileInfo.Delete();
            //    //try to update document again
            //    DoUpdateDocument();
            //}
        }

        private void BuildListOfUsers(IEnumerable users, Permission perm, AclFeed feed)
        {
            string permStr = null;
            switch (perm)
            {
                case Permission.reader: permStr = "reader"; break;
                case Permission.writer: permStr = "writer"; break;
            }

            foreach (object obj in users)
            {
                AclEntry entry = new AclEntry();
                entry.Scope = new AclScope();
                entry.Scope.Type = AclScope.SCOPE_USER;
                entry.Scope.Value = obj.ToString();
                entry.Role = new AclRole(permStr);

                feed.Entries.Add(entry);
            }
        }

        private void dummy()
        {}

        private void RefreshEtag()
        {
            DoLookupRemoteCopy(m_DocInfo);
        }

        public override void UpdateDocumentInfo()
        {
            m_DocInfo = new DocumentInfo(m_App.ActiveDocument.FullName, m_App.ActiveDocument.Name);
            DoLookupRemoteCopy(m_DocInfo);
        }

        public override void DoShareDocumentsAsync(IEnumerable users, Permission perm)
        {
            if (ShareDocument != null)
            {
                ShareInfoCollection info = new ShareInfoCollection(m_DocInfo.m_DocEntry);
                BuildListOfUsers(users, perm, info.m_Feed);

                DoOperationASync<ShareInfoCollection> operation = new DoOperationASync<ShareInfoCollection>(this.ShareDocument, info, this.RefreshEtag);
                operation.StartAction();
            }
        }

        public override void DoOpenLocalCopy(string filePath)
        {
            object fileName = filePath;
            object readOnly = false;
            object isVisible = true;
            // Here is the way to handle parameters you don't care about in .NET
            object missing = System.Reflection.Missing.Value;

            try
            {
                Word.Document wb = m_App.Documents.Open(
                                            ref fileName, 
                                            ref missing, 
                                            ref readOnly, 
                                            ref missing, 
                                            ref missing, 
                                            ref missing, 
                                            ref missing, 
                                            ref missing, 
                                            ref missing, 
                                            ref missing, 
                                            ref missing, 
                                            ref isVisible,
                                            ref missing,
                                            ref missing,
                                            ref missing,
                                            ref missing);

                wb.Save();

                //m_App.ActiveDocument.TrackRevisions = true; 
            }
            catch (Exception ex)
            {
                Utilities.TraceWrapper.LogException("DoOpenLocalCopyShared error: " + ex.Message, ex);
            }
        }

        public override string GetInviteUri()
        { return m_DocInfo.m_DocEntry.AlternateUri.Content; }

        public override void DoOpenDocumentInCloud(DocumentInfo info)
        {
            if (OpenDocumentInCloud != null)
                OpenDocumentInCloud(this, info);
        }

        public override void DoGetDocumentAcl(ShareInfoCollection info)
        {
            if (GetDocumentAcl != null)
                GetDocumentAcl(this, info);
        }
     
        ////////////////////////////////////////////////////////
        // Temporary stubs
        ///////////////////////////////////////////////////////
        public override bool IsDocumentOpened(string path)
        {
            foreach (Word.Document dc in m_App.Documents)
                if (dc.FullName == path)
                    return true;

            return false;
        }

        public override void CloseDocument(string path)
        {
            foreach (Word.Document dc in m_App.Documents)
                if (dc.FullName == path)
                {
                    object saveChanges = Word.WdSaveOptions.wdDoNotSaveChanges;
                    object route = false;
                    dc.Close(ref saveChanges, ref missing, ref route);
                }
        }

        public override void ActivateDocument(string path)
        {
            foreach (Word.Document dc in m_App.Documents)
                if (dc.FullName == path)
                    dc.Activate();
        }

        public override string SupportedFormats()
        {
            return "Word|*.doc|Word 2007|*.docx";
        }

        public override Document.DocumentType DocumentType()
        {
            return Document.DocumentType.Document;
        }

        public override Document.DownloadType DownloadType()
        {
            return Document.DownloadType.doc;
        }

        public override string GetContentText()
        {
            return m_App.ActiveDocument.Content.Text;
        }

        public override void SmartTagActions(Object tag)
        {
            throw new NotImplementedException();
        }

        public override void HighlightSmartTags(string s)
        {
            throw new NotImplementedException();
        }

        public override bool IsLoggedIn()
        {
            return isLoggedIn;
        }
        
        // in Word 2003 no need in this method because we always download/upload only as .xls
        public override void CastContentToExtension(string docPath, Document.DownloadType type)
        {}

        public override void InsertSearchResult(string[] result)
        {
            Word.Selection currentSelection = this.m_App.Selection;

            // Store the user's current Overtype selection
            bool userOvertype = this.m_App.Options.Overtype;

            // Make sure Overtype is turned off.
            if (this.m_App.Options.Overtype)
            {
                this.m_App.Options.Overtype = false;
            }

            // Test to see if selection is an insertion point.
            if (currentSelection.Type == Word.WdSelectionType.wdSelectionIP)
            {
                TypeText(currentSelection, result);
            }
            else
                if (currentSelection.Type == Word.WdSelectionType.wdSelectionNormal)
                {
                    // Move to start of selection.
                    if (this.m_App.Options.ReplaceSelection)
                    {
                        object direction = Word.WdCollapseDirection.wdCollapseStart;
                        currentSelection.Collapse(ref direction);
                    }
                    TypeText(currentSelection, result);
                }
                else
                {
                    // Do nothing.
                }

            // Restore the user's Overtype selection
            this.m_App.Options.Overtype = userOvertype;
        }

        private void TypeText(Word.Selection currentSelection, string[] results)
        {
            currentSelection.TypeText("Title: " + results[0]);
            currentSelection.TypeParagraph();
            currentSelection.TypeText("Description: ");
            currentSelection.TypeParagraph();
            currentSelection.TypeText(results[1]);
            currentSelection.TypeParagraph();
            currentSelection.TypeText("Public profile: ");
            object s = results[2];
            m_App.ActiveDocument.Hyperlinks._Add(
                currentSelection.Range, ref s, ref missing
            );

        }

        public override void DoAddContact(ContactInfo contact)
        {
            if (AddContact != null)
                AddContact(this, contact);
        }

    }
}
